﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AMOOF {
    public class GreekCompare : IComparer<PDF.Greek> {
        public int Compare(PDF.Greek x, PDF.Greek y) {
            return x.ToString().CompareTo(y.ToString());
        }
    }

    public abstract class PDF {

        protected string moment;

        public Object AverageError;
        public Dictionary<int, object> Moments;
        public Dictionary<Greek, double> Greeks;
        //public List<Variable> greeks; // stores the greeks used by the particular function
        private Dictionary<Greek, double> p_greeks;
        //protected double alpha; // these are only initialized right before an output is generated
        //protected double beta;
        //protected double gamma;
        //protected double theta;
        //protected double tau;
        //protected double sigma;
        //protected double mu;
        //protected double alpha2; // these are only initialized right before an output is generated
        //protected double beta2;
        //protected double gamma2;
        //protected double theta2;
        //protected double tau2;
        //protected double sigma2;
        //protected double mu2;
        //protected double p1;
        //protected double p2;


        //public double P1 { set { p1 = value; } get { return p1; } }
        //public double P2 { set { p2 = value; } get { return p2; } }
        public string Moment {
            set { moment = value; }
            get { return moment; }
        }
        public IntegrationRecord CTEsVaRs { set; get; }

        public string name;

        public string lnFunction;
        public string function;
        public abstract double getOutput(double x);
        public abstract double getMoment(double k);
        //public abstract double parametricVolume(double x);
        //public abstract double getMixedOutput(double x);
        //public double getMixedOutput(double x);

        public enum Greek { ALPHA, BETA, GAMMA, THETA, TAU, SIGMA, MU, ALPHA2, BETA2, GAMMA2, THETA2, TAU2, SIGMA2, MU2, P1, P2 };

        public PDF() {
            Greeks = new Dictionary<Greek, double>();
            Moments = new Dictionary<int, object>();
            //greeks = new List<Variable>();
        }

        public virtual String getPeriCommand() {
            String str = "";
            String[] nameStrings = name.Split(' ');
            for (int i = 0; i < nameStrings.Length; i++) {
                str += nameStrings[i];
            }
            str += "_";
            str += "(xVar,";

            var list = Greeks.Keys.ToList();
            list.Sort(new GreekCompare());

            foreach (var kvp in list) {
                str += Greeks[kvp];
                str += ",";
            }

            str = str.Substring(0, str.Length - 1);

            str += ");";
            return str;
        }

        //public Variable getGreek(Greek greek) {
        //    if (p_greeks == null || p_greeks.Count < 1) {
        //        extractGreekValues();
        //    }

        //    if (greek == Greek.P1) {
        //        double val;
        //        if (!p_greeks.TryGetValue(greek, out val)) {
        //            p_greeks.Add(Greek.P1, P1);
        //            val = P1;
        //        }
        //        return new Variable { type = greek, value = val };
        //    }

        //    if (greek == Greek.P2) {
        //        double val;
        //        if (!p_greeks.TryGetValue(greek, out val)) {
        //            p_greeks.Add(Greek.P2, P2);
        //            val = P2;
        //        }
        //        return new Variable { type = greek, value = val };
        //    }

        //    return new Variable { type = greek, value = p_greeks[greek] };

        //}


        //public string getGreeks() {
        //    string temp = "";
        //    foreach (Variable var in greeks) {
        //        temp += var.type + "\t" + var.value + "\n";
        //    }
        //    return temp;
        //}

        public static double standardNormal(double x) {
            double denominator1 = Math.Exp(-1 / 2 * Math.Pow(x, 2));
            double fullDenomerator = Math.Pow(Math.Sqrt(2 * Math.PI), denominator1);
            return 1 / fullDenomerator;
        }

        //// this reduces a lot of code in the subclasses - ???
        ////This is unneeded- ZGH
        //public void extractGreekValues() {
        //    alpha = double.NaN;
        //    beta = double.NaN;
        //    gamma = double.NaN;
        //    theta = double.NaN;
        //    tau = double.NaN;
        //    sigma = double.NaN;
        //    mu = double.NaN;


        //    //TODO: Check if values exist... or add a append other conditionals...
        //    foreach (Variable var in greeks) {
        //        Greek type = var.type;
        //        if (p_greeks == null || p_greeks.Count < 1) {
        //            p_greeks = new Dictionary<Greek, double>();
        //        }


        //        //Implemented by Zachary:
        //        //Replaces conditionals below
        //        Reflector.SetField<double>(type.ToString().ToLower(), this, var.value);

        //        //This is part of a hack I implemented to make it easier to access the greeks...
        //        double val;
        //        if (!p_greeks.TryGetValue(type, out val)) {
        //            p_greeks.Add(type, var.value);
        //        }
        //        else {
        //            p_greeks[type] = var.value;
        //        }
        //        //Implementation end
        //    }
        //}

        //public class Variable {
        //    public Greek type;
        //    public double value;
        //}
    }
}
